package gerenciador_de_memoria;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import sistema_de_arquivos.SistemaArquivos;
import Programas.Processo;
import Escalonador.Escalonador;

/**
 *
 * @author Edilson Anselmo Corrêa Júnior
 */
public class GerenciadorMemoria {

    private int tamSeg;
    private int tamPag;
    private int tamMem;
    private int[][] mem;
    private String algoritmo;
    private Map<Integer, Processo> mapaM;
    private int timeClock;
    private SistemaArquivos sa;
    private List<Processo> lista = new ArrayList<>();

    public class Relogio {

        private class Celula {

            public Processo p;
            public Celula prox;
        }
        private Celula frente;
        private Celula tras;

        public Relogio() {
            frente = null;
            tras = null;
        }

        public void Adiciona(Processo p) {
            this.frente = new Celula();
            this.frente.p = p;
            if (tras == null) {
                tras = frente;
            } else {
                tras.prox = frente;
            }
        }

        public Processo Remove() {
            Processo pout = null;
            if (frente != tras) {
                pout = this.frente.p;
                frente = frente.prox;
                tras.prox = frente;
            } else {
                tras = frente = null;
            }
            return pout;
        }

        public boolean RelogioVazio() {
            if (frente == null) {
                return false;
            } else {
                return true;
            }
        }
    }

    public GerenciadorMemoria(SistemaArquivos sa) {
        this.sa = sa;
        FileReader reader = null;
        try {
            reader = new FileReader("bootstrap.txt");
            BufferedReader leitor = new BufferedReader(reader);
            String linha = leitor.readLine();
            String[] str = linha.split(" ");
            tamSeg = Integer.parseInt(str[0]);
            tamPag = Integer.parseInt(str[1]);
            tamMem = Integer.parseInt(str[2]);
            algoritmo = str[3];
            timeClock = 100;
            mem = new int[tamMem][tamPag];
            for (int i = 0; i < tamMem; i++) {
                for (int j = 0; j < tamPag; j++) {
                    mem[i][j] = 0;
                }
            }
            mapaM = new HashMap<Integer, Processo>();

        } catch (IOException ex) {
            Logger.getLogger(GerenciadorMemoria.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                reader.close();
            } catch (IOException ex) {
                Logger.getLogger(GerenciadorMemoria.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    /**
     * Método responsável por realizar a alocação de processos na memória. O
     * algortimo é escolhido a partir do que é definido no arquivo bootstrap.txt
     *
     * @param p: Processo passado ao Gerenciador de Memória para alocação.
     * @param e: Escalonador passado ao Gerenciador de Memória, caso seja
     * necessário que o Escalonador espere, sua Thread será colocada em espera.
     * @return Retorna 0, caso o processo seja alocado com sucesso, -1, caso o
     * ocorra alguma falha no processo.
     */
    public int alocaProcesso(Processo p, Escalonador e) {

        if (mapaM.containsKey(p.getIdProcesso())) {
            if (mapaM.get(p.getIdProcesso()) == p) {
                return 0;
            }
            this.removeProcesso(p);
        } else {
            Processo pin = sa.swap_get(p.getIdProcesso());
            if (pin == null) {
                if (p.isModificado()) {
                    return 0;
                }
            }
        }

        switch (algoritmo) {
            case "NRU":
                return this.algoritmoNRU(p, e);
            case "FIFO":
                return this.algoritmoFifo(p, e);
            case "Segunda":
                return this.algoritmoSegundaChance(p, e);
            case "Relogio":
                return this.algoritmoRelogio(p, e);
            case "NFU":
                return this.algoritmoNFU(p, e);
            case "Envelhecimento":
                return this.algoritmoEnvelhecimento(p, e);
            case "WS":
                return this.algoritmoConjuntoTrabalho(p, e);
            case "WSClock":
                return this.algoritmoWSClock(p, e);
            default:
                return this.algoritmoFifo(p, e);
        }
    }

    /**
     * Método responsável por procurar um espaço de memória
     *
     * @param i: número de segmentos necessários ao processo.
     * @param p: processo que precisa ser alocado.
     * @return Retorna 0, caso o tamanho de memória suficiente ao processo tenha
     * sido encontrada, 1, caso não seja encontrado um conjunto segmento de
     * memória suficiente ao processo.
     */
    private int procuraSeguimento(int i, Processo p) {

        int segmentoDisponivel = 0;
        int segmentoInicial;

        for (int j = 0; j < tamMem; j++) {
            segmentoInicial = 0;
            segmentoDisponivel = 0;
            for (int k = 0; k < tamPag; k++) {
                if (mem[j][k] == 0) {
                    segmentoDisponivel++;
                } else {
                    segmentoInicial++;
                    segmentoDisponivel = 0;
                }
                
                if (segmentoDisponivel == i) {
                    p.setPag(j);
                    p.setSegInicio(segmentoInicial);
                    for (int l = segmentoInicial; l <= k; l++) {
                        mem[j][l] = p.getIdProcesso();
                    }
                    mapaM.put(p.getIdProcesso(), p);
                    return 0;
                }
            }
        }
        return 1;
    }

    /**
     * Kill1 Método responsável por colocar determinado processo em estado
     * bloqueado.
     *
     * @param pId Indice do processo a ser modificado
     * @return: retorna uma string confirmando se obteve sucesso ao atualizar
     * determinado processo ou nao.
     */
    public String kill1(int pId) {
        boolean containsKey = mapaM.containsKey(pId); // verifica se existe
        if (containsKey) {
            mapaM.get(pId).mudarEstado("Bloqueado");
        } else {
            return "pId inexistente";
        }
        return "Bloqueado";
    }

    /**
     * Kill2 Método responsável por colocar determinado processo em estado
     * pronto.
     *
     * @param pId Indice do processo a ser modificado
     * @return: retorna uma string confirmando se obteve sucesso ao atualizar
     * determinado processo ou nao.
     */
    public String kill2(int pId) {
        boolean containsKey = mapaM.containsKey(pId); // verifica se existe
        if (containsKey) {
            mapaM.get(pId).mudarEstado("Pronto");
        } else {
            return "pId Inexistente";
        }
        return "Pronto";
    }

    /**
     * Kill3 Método responsável por colocar determinado processo em estado
     * executando.
     *
     * @param pId Indice do processo a ser modificado
     * @return: retorna uma string confirmando se obteve sucesso ao atualizar
     * determinado processo ou nao.
     */
    public String kill3(int pId) {
        boolean containsKey = mapaM.containsKey(pId); // verifica se existe
        if (containsKey) {
            mapaM.get(pId).mudarEstado("Executando");
        } else {
            return "pId Inexistente";
        }
        return "Executando";
    }

    /**
     * KillAll Método responsável pela remoção de um grupo de processos da
     * memória
     *
     * @param gId Indice do grupo a ser removido
     * @return Retorna uma String com mensagem de sucesso ou erro
     */
    public String killAll(int gId) {
        Iterator<Map.Entry<Integer, Processo>> it = mapaM.entrySet().iterator();
        boolean encontrado = false;
        while (it.hasNext()) {
            Map.Entry<Integer, Processo> entrada = it.next();
            if (entrada.getValue().getGroupId() == gId) {
                removeProcesso(entrada.getValue());
                encontrado = true;
            }
        }
        if(sa.swap_get_by_gid(gId) != null){
            return "Grupo Removido";
        }
        if (!encontrado) {
            return "gId Inexistente";
        }
        
        return "Grupo Removido";
    }

    /**
     * Mem Método responsável por listar todos processos juntamente com algumas
     * iformações.
     *
     * @return: retorna uma string contendo algumas informações dos processos.
     */
    public String mem() {

        Iterator<Map.Entry<Integer, Processo>> it = mapaM.entrySet().iterator();
        String lista = "ID\tGRUPO ID\tTEMPO\tPRIORIDADE\tTAMANHO\n";
        while (it.hasNext()) {
            Map.Entry<Integer, Processo> entrada = it.next();
            Processo p = entrada.getValue();
            lista += p.getIdProcesso() + "\t" + p.getGroupId() + "\t" + p.getTempoDeExecucao() + "\t" + p.getPrioridade() + "\t" + p.getTamanho() + "\n";
        }
        return lista;
    }

    /**
     * Kill 9 Método responsável pela remoção de um processo da memória
     *
     * @param pId Indice do processo a ser removido
     * @return Retorna uma String com mensagem de sucesso ou erro
     */
    public String kill9(int pId) {
        boolean containsKey = mapaM.containsKey(pId); // verifica se existe
        if (containsKey) { // contains = true remove o processo da memoria e da swap
            removeProcesso(mapaM.get(pId)); // remove processo
            sa.swap_get(pId); // remove da swap
        } else {
            return "pID inexistente."; // Mensagem de erro
        }
        return "Sucesso"; // Mensagem de sucesso
    }

    /**
     * Método responsável por retornar os processos juntamente com seus estados.
     * Bloqueado, Executando ou Pronto.
     *
     * @return: retorna uma string contendo toda a informação dos processos.
     */
    public String schell() {
        Iterator<Map.Entry<Integer, Processo>> it = mapaM.entrySet().iterator();
        String lista = "ID\tGRUPO ID\tESTADO\n";
        while (it.hasNext()) {
            Map.Entry<Integer, Processo> entrada = it.next();
            Processo p = entrada.getValue();
            lista += p.getIdProcesso() + "\t" + p.getGroupId() + "\t" + p.getEstado() + "\n";
        }
        return lista;
    }

    /**
     * Método responsável por retorna # ou * representando a memória após
     * precorrer a matriz que representa a memória.
     *
     * @return Retorna uma String contendo #(posição ocupada) e *(posição vazia)
     */
    public String memVisual() {
        int i, j;
        String visual = "Disposição da Memória\n";
        for (i = 0; i < tamMem; i++) {
            visual += "\n";
            for (j = 0; j < tamPag; j++) {
                if (mem[i][j] == 0) {
                    visual += "*";
                } else {
                    visual += "#";
                }
            }
        }
        visual += "\n# = posição ocupada, * = posição vazia.";
        return visual;
    }

    /**
     * memCopy Método é responsável por enviar todos processos para a swap
     *
     * @return Retorna uma String com mensagem de sucesso ou erro
     */
    public String memCopy() {
        Iterator<Map.Entry<Integer, Processo>> it = mapaM.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<Integer, Processo> entrada = it.next();
            enviaSwap(entrada.getValue());
        }
        return "Sucesso";
    }

    /**
     * Método responsável por limpar a memória. Esse método limpa tanto a matriz
     * que representa a memória quanto a Hash, que é responsável pelo seu
     * mapeamento.
     *
     * @return: retorna uma mensagem de sucesso da operação.
     */
    public String memClear() {
        mem = new int[tamMem][tamPag];
        for (int i = 0; i < tamMem; i++) {
            for (int j = 0; j < tamPag; j++) {
                mem[i][j] = 0;
            }
        }
        mapaM = new HashMap<Integer, Processo>();
        return "Memoria Limpa!";
    }

    /**
     * Métoro responsável por enviar um processo à swap.
     *
     * @param p: processo que deve ser enviado a swap.
     */
    public void enviaSwap(Processo p) {
        sa.swap_put(p.getIdProcesso(), p);
    }

    /**
     * Método responsável por remover determinado elemento tanto do mapa quanto
     * da matriz que representa a memória.
     *
     * @param p: processo que deve ser removido.
     */
    public void removeProcesso(Processo p) {
        mapaM.remove(p.getIdProcesso());
        for (int j = 0; j < tamMem; j++) {
            for (int k = 0; k < tamPag; k++) {
                if (mem[j][k] == p.getIdProcesso()) {
                    mem[j][k] = 0;
                }
            }
        }
    }

    /**
     * Algoritmo NRU (Not Recent Used) a politica do NRU separa os processos em
     * quatro classes: Classe 0: Não referenciado, não modificado. Classe 1: Não
     * referenciado, modificado. Classe 2: Referenciado, não modificado. Classe
     * 3: referenciado modificado. Remove o processo da classe mais baixa que
     * não esteja vazio.
     *
     * @param p Processo que precisa ser alocado na memoria
     * @param e Escalonador
     * @return Retorna 0 se obteve sucesso na alocação do processo na memoria e
     * -1, caso o ocorra alguma falha no processo de alocação.
     */
    public int algoritmoNRU(Processo p, Escalonador e) {
        if (p.isReferenciado() || p.isModificado()) {
            if (!p.isModificado()) {
                //sobrescreve processo
                int t = p.getTamanho() % tamSeg == 0 ? p.getTamanho() / tamSeg : ((p.getTamanho() + tamSeg) / tamSeg);
                procuraSeguimento(t, p);
            } else {
                if (p.getTamanho() > tamPag) {
                    //Limite de memória atingido
                    return -1;
                } else {
                    int t = p.getTamanho() % tamSeg == 0 ? p.getTamanho() / tamSeg : ((p.getTamanho() + tamSeg) / tamSeg);
                    if (this.procuraSeguimento(t, p) != 0) {
                        do {
                            // Algoritmo/Política
                            //Processo a ser removido
                            Processo pout = null;
                            Iterator<Map.Entry<Integer, Processo>> it = mapaM.entrySet().iterator();
                            /**
                             * Classe 0 Processo que não foi nem referenciado
                             * nem modificado Caso encontre algum processo na
                             * classe 0 é ele quem vai ser retirado
                             */
                            if (pout == null) {
                                while (it.hasNext()) {
                                    Map.Entry<Integer, Processo> entrada = it.next();
                                    if (!entrada.getValue().isReferenciado() && !entrada.getValue().isModificado()) {
                                        pout = entrada.getValue();
                                    }
                                }
                            }
                            /**
                             * Classe 1 Processo foi referenciado mas não foi
                             * modificado Caso não encontre um processo na
                             * classe 0 mas encontre um nessa classe é ele quem
                             * vai ser retirado
                             */
                            if (pout == null) {
                                while (it.hasNext()) {
                                    Map.Entry<Integer, Processo> entrada = it.next();
                                    if (entrada.getValue().isReferenciado() && !entrada.getValue().isModificado()) {
                                        pout = entrada.getValue();
                                    }
                                }
                            }
                            /**
                             * Classe 2 Processo não foi referenciado mas foi
                             * modificado Caso não tenha encontrado um processo
                             * nas classes anterios e encontre um processo nessa
                             * classe ele será retirado
                             */
                            if (pout == null) {
                                while (it.hasNext()) {
                                    Map.Entry<Integer, Processo> entrada = it.next();
                                    if (!entrada.getValue().isReferenciado() && entrada.getValue().isModificado()) {
                                        pout = entrada.getValue();
                                    }
                                }
                            }
                            /**
                             * Classe 3 Processo foi referenciado e foi
                             * modificado Caso não tenha encontrado um processo
                             * nas classes anterios e encontre um processo nessa
                             * classe ele será retirado
                             */
                            if (pout == null) {
                                while (it.hasNext()) {
                                    Map.Entry<Integer, Processo> entrada = it.next();
                                    if (entrada.getValue().isReferenciado() && entrada.getValue().isModificado()) {
                                        pout = entrada.getValue();
                                    }
                                }
                            }
                            // Enquanto memória insuficiente 
                            // arranca o processo pout da memória e coloca na swap  
                            removeProcesso(pout);
                            enviaSwap(pout);
                        } while (this.procuraSeguimento(t, p) != 0);
                        return 0;
                    } else {
                        return 0;
                    }
                }
            }
        } else {
            int t = p.getTamanho() % tamSeg == 0 ? p.getTamanho() / tamSeg : ((p.getTamanho() + tamSeg) / tamSeg);
            if (t > tamPag) {
                //Limite de memória atingido
                return -1;
            }
            if (this.procuraSeguimento(t, p) != 0) {
                do {
                    // Algoritmo/Política
                    //Processo a ser retirado
                    Processo pout = null;
                    Iterator<Map.Entry<Integer, Processo>> it = mapaM.entrySet().iterator();
                    /**
                     * Classe 0 Processo que não foi nem referenciado nem
                     * modificado Caso encontre algum processo na classe 0 é ele
                     * quem vai ser retirado
                     */
                    if (pout == null) {
                        while (it.hasNext()) {
                            Map.Entry<Integer, Processo> entrada = it.next();
                            if (!entrada.getValue().isReferenciado() && !entrada.getValue().isModificado()) {
                                pout = entrada.getValue();
                            }
                        }
                    }
                    /**
                     * Classe 1 Processo foi referenciado mas não foi modificado
                     * Caso não encontre um processo na classe 0 mas encontre um
                     * nessa classe é ele quem vai ser retirado
                     */
                    if (pout == null) {
                        while (it.hasNext()) {
                            Map.Entry<Integer, Processo> entrada = it.next();
                            if (entrada.getValue().isReferenciado() && !entrada.getValue().isModificado()) {
                                pout = entrada.getValue();
                            }
                        }
                    }
                    /**
                     * Classe 2 Processo não foi referenciado mas foi modificado
                     * Caso não tenha encontrado um processo nas classes
                     * anterios e encontre um processo nessa classe ele será
                     * retirado
                     */
                    if (pout == null) {
                        while (it.hasNext()) {
                            Map.Entry<Integer, Processo> entrada = it.next();
                            if (!entrada.getValue().isReferenciado() && entrada.getValue().isModificado()) {
                                pout = entrada.getValue();
                            }
                        }
                    }
                    /**
                     * Classe 3 Processo foi referenciado e foi modificado Caso
                     * não tenha encontrado um processo nas classes anterios e
                     * encontre um processo nessa classe ele será retirado
                     */
                    if (pout == null) {
                        while (it.hasNext()) {
                            Map.Entry<Integer, Processo> entrada = it.next();
                            if (entrada.getValue().isReferenciado() && entrada.getValue().isModificado()) {
                                pout = entrada.getValue();
                            }
                        }
                    }
                    // Enquanto memória insuficiente 
                    // arranca o processo pout da memória e coloca na swap 
                    removeProcesso(pout);
                    enviaSwap(pout);
                } while (this.procuraSeguimento(t, p) != 0);
                return 0;
            } else {
                return 0;
            }
        }
        return -1;
    }

    /**
     * Algoritmo FIFO. Remove o processo com maior timestamp ou seja o mais
     * velho. que é a cabeça a fila.
     *
     * @param p Processo a ser removido
     * @param e Escalonador
     * @return Retorna 0 se obteve sucesso na alocação do processo na memoria e
     * -1, caso o ocorra alguma falha no processo de alocação.
     */
    public int algoritmoFifo(Processo p, Escalonador e) {
        if (p.isReferenciado() || p.isModificado()) {
            if (!p.isModificado()) {
                //sobrescreve processo
                int t = p.getTamanho() % tamSeg == 0 ? p.getTamanho() / tamSeg : ((p.getTamanho() + tamSeg) / tamSeg);
                procuraSeguimento(t, p);
            } else {
                if (p.getTamanho() > tamPag) {
                    //Limite de memória atingido
                    return -1;
                } else {
                    int t = p.getTamanho() % tamSeg == 0 ? p.getTamanho() / tamSeg : ((p.getTamanho() + tamSeg) / tamSeg);
                    if (this.procuraSeguimento(t, p) != 0) {
                        do {
                            // Algoritmo/Política
                            //Incializa a cabeça para fins de comparação
                            int cabeca = -1;
                            //Processo a ser removido.
                            Processo pout = null;
                            //Inicializa interator
                            Iterator<Map.Entry<Integer, Processo>> it = mapaM.entrySet().iterator();
                            //Faz a verificação de qual processo, tem o maior timestamp.
                            while (it.hasNext()) {
                                Map.Entry<Integer, Processo> entrada = it.next();
                                if (entrada.getValue().getTimestemp() > cabeca) {
                                    cabeca = (int) entrada.getValue().getTimestemp();
                                    pout = entrada.getValue();
                                }
                            }
                            //Ranca cabeca da Hash e da Matriz e manda pra swap
                            // Enquanto memória insuficiente 
                            // arranca coisa da memória e coloca na swap 
                            removeProcesso(pout);
                            enviaSwap(pout);
                        } while (this.procuraSeguimento(t, p) != 0);
                        return 0;
                    } else {
                        return 0;
                    }
                }
            }
        } else {
            int t = p.getTamanho() % tamSeg == 0 ? p.getTamanho() / tamSeg : ((p.getTamanho() + tamSeg) / tamSeg);
            if (t > tamPag) {
                //Limite de memória atingido
                return -1;
            }
            if (this.procuraSeguimento(t, p) != 0) {
                do {
                    // Algoritmo/Política
                    //Incializa variável para fins de comparação.
                    int cabeca = -1;
                    //Processo a ser removido.
                    Processo pout = null;
                    //Incializa interator
                    Iterator<Map.Entry<Integer, Processo>> it = mapaM.entrySet().iterator();
                    //Verifica qual o maior timestamp.
                    while (it.hasNext()) {
                        Map.Entry<Integer, Processo> entrada = it.next();
                        if (entrada.getValue().getTimestemp() > cabeca) {
                            cabeca = (int) entrada.getValue().getTimestemp();
                            pout = entrada.getValue();
                        }
                    }
                    //Ranca cabeca da Hash e da Matriz e manda pra swap
                    // Enquanto memória insuficiente 
                    // arranca coisa da memória e coloca na swap 
                    removeProcesso(pout);
                    enviaSwap(pout);
                } while (this.procuraSeguimento(t, p) != 0);
                return 0;
            } else {
                return 0;
            }
        }
        return -1;
    }

    /**
     * Algoritmo Conjunto de Trabalho: Procura um processo que não esteja no
     * conjunto de trabalho e removê-lo da memória.
     *
     * A cada page falt, no caso desse algoritmo seria falta de processos, a
     * tabela de processos inteira é buscada. À medida que cada entrada é
     * processada, examine R: Se R = 1, escreva o tempo virtual corrente no
     * campo Tempo do Último Uso (InstUltUso), indicando que o processo estava
     * em uso no instante da page fault, ou seja, estava no working set. Assim
     * ele não é candidato a remoção. Se R=0, o processo não foi referenciado no
     * ciclo atual, e pode ser um candidato à remoção. Nesse caso, se sua idade
     * for maior que o intervalo timeClock do working set, ele não está nele, e
     * pode ser removido. A busca continua atualizando as demais entradas. Se,
     * contudo, a idade for menor que timeClock, o processo é poupado. Contudo,
     * o processo com maior idade é marcado. Se nenhum candidato for encontrado
     * (todas os processos estão no working set), substitua o processo mais
     * velho, dentre as com R=0 Na pior das hipóteses, todas os processos foram
     * referenciados, assim um deles será escolhido aleatoriamente para remoção.
     *
     * @param p Processo que precisa ser alocado na memoria
     * @param e Escalonador
     * @return Retorna 0 se obteve sucesso na alocação do processo na memoria e
     * -1, caso o ocorra alguma falha no processo de alocação.
     */
   public int algoritmoConjuntoTrabalho(Processo p, Escalonador e) {
        if (p.isReferenciado() || p.isModificado()) {
            if (!p.isModificado()) {
                //sobrescreve processo
                int t = p.getTamanho() % tamSeg == 0 ? p.getTamanho() / tamSeg : ((p.getTamanho() + tamSeg) / tamSeg);
                procuraSeguimento(t, p);
            } else {
                if (p.getTamanho() > tamPag) {
                    //Limite de memória atingido
                    return -1;
                } else {
                    int t = p.getTamanho() % tamSeg == 0 ? p.getTamanho() / tamSeg : ((p.getTamanho() + tamSeg) / tamSeg);
                    if (this.procuraSeguimento(t, p) != 0) {
                        do {
                            Iterator<Map.Entry<Integer, Processo>> it = mapaM.entrySet().iterator();
                            boolean encontrado = false;
                            Timestamp timeAt = new Timestamp(System.currentTimeMillis());   //Tempo atual
                            double timeOld = timeAt.getTime();//Tempo Atual é o tempo de referencia para verifar o processo mais velho
                            int idOld = -1; //Armazena o Id do processo mais velho
                            do {
                                Map.Entry<Integer, Processo> entrada = it.next();
                                if (entrada.getValue().isReferenciado()) {//Se o processo foi referenciado
                                    mapaM.get(entrada.getKey()).setReferenciado(false);//Coloca o bit R em 0(false)
                                    timeAt = new Timestamp(System.currentTimeMillis());   //Tempo atual
                                    mapaM.get(entrada.getKey()).setInstUltUso(timeAt);      //Atualiza o tempo
                                } else {    //Se o processo nao foi referenciado
                                    timeAt = new Timestamp(System.currentTimeMillis());   //Tempo atual
                                    if (timeAt.getTime() - entrada.getValue().getInstUltUso().getTime() >= timeClock) { //Verificação de tempo fora do conjunto de trabalho
                                        //Valida copia em disco
                                        enviaSwap(entrada.getValue());
                                        //Remove da Memoria e da tabela
                                        removeProcesso(entrada.getValue());
                                        encontrado = true;
                                    } else {  //Verifica o processo mais velho
                                        if (entrada.getValue().getInstUltUso().getTime() <= timeOld) {
                                            timeOld = entrada.getValue().getInstUltUso().getTime();
                                            idOld = entrada.getKey();
                                        }
                                    }
                                }
                                if ((!it.hasNext()) && (!encontrado)) {

                                    if (idOld != -1) {
                                        //Valida Copida em disco
                                        enviaSwap(mapaM.get(idOld));
                                        //Remove o processo de id idOl
                                        removeProcesso(mapaM.get(idOld));
                                    } else {
                                        //Valida Copida em disco
                                        enviaSwap(entrada.getValue());

                                        //Retira um processo aleatoriamente
                                        //(Para nao ter mais gasto procurando processos, sera retirado o processo atualmente apontado)
                                        removeProcesso(entrada.getValue());
                                    }
                                    encontrado = true;
                                } else {
                                    if (encontrado) { //Atualiza entradas restantes
                                        while (it.hasNext()) {
                                            entrada = it.next();
                                            if (entrada.getValue().isReferenciado()) {//Se o processo foi referenciado
                                                mapaM.get(entrada.getKey()).setReferenciado(false);//Coloca o bit R em 0(false)
                                                timeAt = new Timestamp(System.currentTimeMillis());   //Tempo atual
                                                mapaM.get(entrada.getKey()).setInstUltUso(timeAt);      //Atualiza o tempo
                                            }

                                        }
                                    }
                                }
                            } while (!encontrado);
                        } while (this.procuraSeguimento(t, p) != 0);
                        return 0;
                    } else {
                        return 0;
                    }
                }
            }
        } else {
            int t = p.getTamanho() % tamSeg == 0 ? p.getTamanho() / tamSeg : ((p.getTamanho() + tamSeg) / tamSeg);
            if (t > tamPag) {
                //Limite de memória atingido
                return -1;
            }
            if (this.procuraSeguimento(t, p) != 0) {
                do {
                            Iterator<Map.Entry<Integer, Processo>> it = mapaM.entrySet().iterator();
                            boolean encontrado = false;
                            Timestamp timeAt = new Timestamp(System.currentTimeMillis());   //Tempo atual
                            double timeOld = timeAt.getTime();//Tempo Atual é o tempo de referencia para verifar o processo mais velho
                            int idOld = -1; //Armazena o Id do processo mais velho
                            do {
                                Map.Entry<Integer, Processo> entrada = it.next();
                                if (entrada.getValue().isReferenciado()) {//Se o processo foi referenciado
                                    mapaM.get(entrada.getKey()).setReferenciado(false);//Coloca o bit R em 0(false)
                                    timeAt = new Timestamp(System.currentTimeMillis());   //Tempo atual
                                    mapaM.get(entrada.getKey()).setInstUltUso(timeAt);      //Atualiza o tempo
                                } else {    //Se o processo nao foi referenciado
                                    timeAt = new Timestamp(System.currentTimeMillis());   //Tempo atual
                                    if (timeAt.getTime() - entrada.getValue().getInstUltUso().getTime() >= timeClock) { //Verificação de tempo fora do conjunto de trabalho
                                        //Valida copia em disco
                                        enviaSwap(entrada.getValue());
                                        //Remove da Memoria e da tabela
                                        removeProcesso(entrada.getValue());
                                        encontrado = true;
                                    } else {  //Verifica o processo mais velho
                                        if (entrada.getValue().getInstUltUso().getTime() <= timeOld) {
                                            timeOld = entrada.getValue().getInstUltUso().getTime();
                                            idOld = entrada.getKey();
                                        }
                                    }
                                }
                                if ((!it.hasNext()) && (!encontrado)) {

                                    if (idOld != -1) {
                                        //Valida Copida em disco
                                        enviaSwap(mapaM.get(idOld));
                                        //Remove o processo de id idOl
                                        removeProcesso(mapaM.get(idOld));
                                    } else {
                                        //Valida Copida em disco
                                        enviaSwap(entrada.getValue());

                                        //Retira um processo aleatoriamente
                                        //(Para nao ter mais gasto procurando processos, sera retirado o processo atualmente apontado)
                                        removeProcesso(entrada.getValue());
                                    }
                                    encontrado = true;
                                } else {
                                    if (encontrado) { //Atualiza entradas restantes
                                        while (it.hasNext()) {
                                            entrada = it.next();
                                            if (entrada.getValue().isReferenciado()) {//Se o processo foi referenciado
                                                mapaM.get(entrada.getKey()).setReferenciado(false);//Coloca o bit R em 0(false)
                                                timeAt = new Timestamp(System.currentTimeMillis());   //Tempo atual
                                                mapaM.get(entrada.getKey()).setInstUltUso(timeAt);      //Atualiza o tempo
                                            }

                                        }
                                    }
                                }
                            } while (!encontrado);
                        } while (this.procuraSeguimento(t, p) != 0);
                return 0;
            } else {
                return 0;
            }
        }
        return -1;
    }

    /**
     * Algoritmo WSClock = Relógio + WS: Cada entrada contém o tempo de último
     * uso, além dos bits R e M.
     *
     * A cada page fault, a página dacabeça é examinada primeiro Se o bit R for
     * igual a 1: o processo foi referenciado e não é candidato à remoção da
     * memória, o bit R é entao colocado em zero e o ponteiro avança para o
     * próximo processo.
     *
     * Se o bit R for igual a 0: se sua idade for maior do que o intervalo
     * "timeClock" e se seu processo estiver limpo, entao ele nao se encontra no
     * conjunto de trabalho, assim esse processo pode ser retirado para a
     * entrada de um processo novo, mas se o processo estiver sujo, entao ele
     * nao poderá ser substituido imediatamente, assim uma copia é validada em
     * disco e o bit M é colocado em 0.
     *
     * Caso o ponteiro dê uma volta no relogio, entao: 1.Pelo menos uma escrita
     * foi escalonada: O ponteiro continua a se mover a procura de uma pagina
     * limpa, visto que pelo menos uma escrita foi feita.
     *
     * 2.Nenhuma escrita foi escalonada:
     *
     * Caso todos os processos estejam dentro do conjunto de trabalho, é
     * retidado aquele que estiver limpo.
     *
     * @param p Processo que precisa ser alocado na memoria
     * @param e Escalonador
     * @return Retorna 0 se obteve sucesso na alocação do processo na memoria e
     * -1, caso o ocorra alguma falha no processo de alocação.
     */
    public int algoritmoWSClock(Processo p, Escalonador e) {
        if (p.isReferenciado() || p.isModificado()) {
            if (!p.isModificado()) {
                //sobrescreve processo
                int t = p.getTamanho() % tamSeg == 0 ? p.getTamanho() / tamSeg : ((p.getTamanho() + tamSeg) / tamSeg);
                procuraSeguimento(t, p);
            } else {
                if (p.getTamanho() > tamPag) {
                    //Limite de memória atingido
                    return -1;
                } else {
                    int t = p.getTamanho() % tamSeg == 0 ? p.getTamanho() / tamSeg : ((p.getTamanho() + tamSeg) / tamSeg);
                    if (this.procuraSeguimento(t, p) != 0) {
                        do {
                            Iterator<Map.Entry<Integer, Processo>> it = mapaM.entrySet().iterator();
                            boolean encontrado = false; //Indica se um proceesso a ser retirado foi encontrado
                            boolean valida = false; //Indica que uma copia foi enviada para o disco e que esta disponivel para ser removida
                            Timestamp timeAt = new Timestamp(System.currentTimeMillis());   //Tempo atual
                            int idLimpo = -1; //Armazena o id de um processo do conjunto de trabalho que esteja limpo
                            //Relogio
                            do {
                                Map.Entry<Integer, Processo> entrada = it.next();
                                if (entrada.getValue().isReferenciado()) {
                                    //Coloca o Bit R do processo para 0
                                    mapaM.get(entrada.getKey()).setReferenciado(false);

                                } else {
                                    timeAt = new Timestamp(System.currentTimeMillis());   //Tempo atual
                                    if (timeAt.getTime() - entrada.getValue().getInstUltUso().getTime() >= timeClock) { //Verificação de tempo
                                        if (!entrada.getValue().isModificado()) {
                                            //Retira da Hash e da Matriz
                                            enviaSwap(entrada.getValue());
                                            removeProcesso(entrada.getValue());
                                            encontrado = true;
                                        } else {
                                            //Valida copia em disco
                                            mapaM.get(entrada.getKey()).setModificado(false);
                                            valida = true;
                                        }
                                    } else {
                                        if (!entrada.getValue().isModificado()) {
                                            idLimpo = entrada.getKey();//Armazena processo do WS que esteja limpo                                        
                                        }
                                    }
                                    if ((!it.hasNext()) && (!encontrado)) {
                                        if (valida) {
                                            it = mapaM.entrySet().iterator();//reinicia o relogio
                                        } else {
                                            if (idLimpo != -1) {
                                                //Remove o processo de id idLimpo
                                                enviaSwap(entrada.getValue());
                                                removeProcesso(mapaM.get(idLimpo));
                                                encontrado = true;
                                            } else {
                                                it = mapaM.entrySet().iterator();
                                                //Inicia o Relogio novamente em busca de uma pagina nao referenciada
                                            }
                                        }
                                    }
                                }
                            } while (!encontrado);
                        } while (this.procuraSeguimento(t, p) != 0);
                        return 0;
                    } else {
                        return 0;
                    }
                }
            }
        } else {
            int t = p.getTamanho() % tamSeg == 0 ? p.getTamanho() / tamSeg : ((p.getTamanho() + tamSeg) / tamSeg);
            if (t > tamPag) {
                //Limite de memória atingido
                return -1;
            }
            if (this.procuraSeguimento(t, p) != 0) {
                do {
                    Iterator<Map.Entry<Integer, Processo>> it = mapaM.entrySet().iterator();
                    boolean encontrado = false; //Indica se um proceesso a ser retirado foi encontrado
                    boolean valida = false; //Indica que uma copia foi enviada para o disco e que esta disponivel para ser removida
                    Timestamp timeAt = new Timestamp(System.currentTimeMillis());   //Tempo atual
                    int idLimpo = -1; //Armazena o id de um processo do conjunto de trabalho que esteja limpo
                    //Relogio
                    do {
                        Map.Entry<Integer, Processo> entrada = it.next();
                        if (entrada.getValue().isReferenciado()) {
                            //Coloca o Bit R do processo para 0
                            mapaM.get(entrada.getKey()).setReferenciado(false);

                        } else {
                            timeAt = new Timestamp(System.currentTimeMillis());   //Tempo atual
                            if (timeAt.getTime() - entrada.getValue().getInstUltUso().getTime() >= timeClock) { //Verificação de tempo
                                if (!entrada.getValue().isModificado()) {
                                    //Retira da Hash e da Matriz
                                    enviaSwap(entrada.getValue());
                                    removeProcesso(entrada.getValue());
                                    encontrado = true;
                                } else {
                                    //Valida copia em disco
                                    mapaM.get(entrada.getKey()).setModificado(false);
                                    valida = true;
                                }
                            } else {
                                if (!entrada.getValue().isModificado()) {
                                    idLimpo = entrada.getKey();//Armazena processo do WS que esteja limpo                                        
                                }
                            }
                            if ((!it.hasNext()) && (!encontrado)) {
                                if (valida) {
                                    it = mapaM.entrySet().iterator();//reinicia o relogio
                                } else {
                                    if (idLimpo != -1) {
                                        //Remove o processo de id idLimpo
                                        enviaSwap(entrada.getValue());
                                        removeProcesso(mapaM.get(idLimpo));
                                        encontrado = true;
                                    } else {
                                        it = mapaM.entrySet().iterator();
                                        //Inicia o Relogio novamente em busca de uma pagina nao referenciada
                                    }
                                }
                            }
                        }
                    } while (!encontrado);
                } while (this.procuraSeguimento(t, p) != 0);
                return 0;
            } else {
                return 0;
            }
        }
        return -1;
    }
    //Algoritmo Segunda Chance

    /**
     *
     * Método algoritmo Segunda Chance responsavel pela procura de um local na
     * memoria.
     *
     * Inspeciona o bit R da página mais velha: Se for 0, ele é velho e não foi
     * usada recentemente é colocado na swap. Se for 1, o bit é feito 0 e a
     * processo é colocada no final da fila, Seu tempo de carga é modificado,
     * fazendo parecer que recém chegou na memória (recebe uma segunda chance) e
     * a busca continua
     *
     * @param e Escalonador
     * @param p Processo que precisa ser alocado na memoria
     * @return Retorna 0 se obteve sucesso na alocação do processo na memoria e
     * -1, caso o ocorra alguma falha no processo de alocação.
     */
    public int algoritmoSegundaChance(Processo p, Escalonador e) {

        lista = new ArrayList<>();
        boolean busca = true;
        if (p.isReferenciado() || p.isModificado()) {
            if (!p.isModificado()) {
                //sobrescreve processo
                int t = p.getTamanho() % tamSeg == 0 ? p.getTamanho() / tamSeg : ((p.getTamanho() + tamSeg) / tamSeg);
                procuraSeguimento(t, p);
            } else {
                if (p.getTamanho() > tamPag) {
                    //Limite de memória atingido
                    return -1;
                } else {
                    int t = p.getTamanho() % tamSeg == 0 ? p.getTamanho() / tamSeg : ((p.getTamanho() + tamSeg) / tamSeg);
                    if (this.procuraSeguimento(t, p) != 0) {
                        do {
                            // Algoritmo/Política
                            // Enquanto memória insuficiente
                            // arranca coisa da memória e coloca na swap
                            Iterator<Map.Entry<Integer, Processo>> it = mapaM.entrySet().iterator();
                            int id = 0;
                            int cabecaFila = -1;
                            if (busca) { // Se busca = true prenche a lista
                                it = mapaM.entrySet().iterator();
                                while (it.hasNext()) {
                                    Map.Entry<Integer, Processo> entrada = it.next();
                                    lista.add(entrada.getValue());
                                }
                            }
                            Iterator<Processo> entradaLista = lista.iterator();
                            int num = 0;
                            while (entradaLista.hasNext()) { // Busca o maior timestamp
                                Processo pF = entradaLista.next();
                                if (pF.getTimestemp() > cabecaFila) {
                                    cabecaFila = (int) pF.getTimestemp();  // Pegar o Timestamp(tempo) do processo
                                    id = pF.getIdProcesso(); // id do processo
                                }
                            }
                            it = mapaM.entrySet().iterator();
                            while (it.hasNext()) {
                                Map.Entry<Integer, Processo> entrada = it.next();
                                if (entrada.getValue().getIdProcesso() == id) {
                                    if (entrada.getValue().isReferenciado()) {/* Se o processo esta referenciado
                                         * coloca no fim da fila(timestamp = 0(como Fornece Novo) e seta R=0(nao referenciado)) 
                                         * sendo assim dando uma segunda chance para o processo e continua a busca
                                         */
                                        lista.remove(entrada.getValue());// Remove
                                        entrada.getValue().setReferenciado(false); //Seta o bit R do processo para 0(false, ou seja, nao referenciado)
                                        entrada.getValue().setTimestemp(0); // Timestamp Recebe 0 como fornece novo                                         
                                        lista.add(entrada.getValue());// Adiciona com o valor modificado                          
                                        busca = false;
                                    } else if ((entrada.getValue().isReferenciado()) == (false)) {
                                        lista.remove(entrada.getValue());// remove da fila
                                        busca = false;
                                        // Arranca o processo da memória e coloca na swap 
                                        removeProcesso(entrada.getValue());
                                        enviaSwap(entrada.getValue());
                                    }
                                }
                            }

                        } while (this.procuraSeguimento(t, p) != 0);
                        return 0;
                    } else {
                        return 0;
                    }
                }
            }
        } else {
            int t = p.getTamanho() % tamSeg == 0 ? p.getTamanho() / tamSeg : ((p.getTamanho() + tamSeg) / tamSeg);
            busca = true;
            if (t > tamPag) {
                //Limite de memória atingido
                return -1;
            }
            if (this.procuraSeguimento(t, p) != 0) {
                do {
                    // Algoritmo/Política
                    // Enquanto memória insuficiente
                    // arranca coisa da memória e coloca na swap
                    Iterator<Map.Entry<Integer, Processo>> it = mapaM.entrySet().iterator();
                    int id = 0;
                    int cabecaFila = -1;
                    boolean encontrado = false;
                    if (busca) { // Se busca = true prenche a lista
                        it = mapaM.entrySet().iterator();
                        while (it.hasNext()) {
                            Map.Entry<Integer, Processo> entrada = it.next();
                            lista.add(entrada.getValue());
                        }
                    }
                    Iterator<Processo> entradaLista = lista.iterator();
                    int num = 0;
                    while (entradaLista.hasNext()) { // Busca o maior timestamp
                        Processo pF = entradaLista.next();
                        if (pF.getTimestemp() > cabecaFila) {
                            cabecaFila = (int) pF.getTimestemp();  // Pegar o Timestamp(tempo) do processo
                            id = pF.getIdProcesso(); // id do processo
                        }
                    }
                    it = mapaM.entrySet().iterator();
                    while (busca) {
                        Map.Entry<Integer, Processo> entrada = it.next();
                        if (entrada.getValue().getIdProcesso() == id) {
                            if (entrada.getValue().isReferenciado()) {/* Se o processo esta referenciado
                                 * coloca no fim da fila(timestamp = 0(como Fornece Novo) e seta R=0(nao referenciado)) 
                                 * sendo assim dando uma segunda chance para o processo e continua a busca
                                 */
                                lista.remove(entrada.getValue());// Remove 
                                entrada.getValue().setReferenciado(false); //Seta o bit R do processo para 0(false, ou seja, nao referenciado)
                                entrada.getValue().setTimestemp(0); // Timestamp Recebe 0 como fornece novo                               
                                lista.add(entrada.getValue());// Adiciona com o valor modificado
                                busca = false;
                            } else if ((entrada.getValue().isReferenciado()) == (false)) {
                                lista.remove(entrada.getValue());// remove da fila
                                busca = false;
                                // Arranca o processo da memória e coloca na swap 
                                removeProcesso(entrada.getValue());
                                enviaSwap(entrada.getValue());
                            }
                        }
                    }

                } while (this.procuraSeguimento(t, p) != 0);
                return 0;
            } else {
                return 0;
            }
        }
        return -1;
    }

    /**
     * Algoritmo NFU (Not Frequently used) Remove o processo que tiver o menor
     * contador de refernciamento
     *
     * @param p Processo a ser removido
     * @param e Escalonador
     * @return Retorna 0 se obteve sucesso na alocação do processo na memoria e
     * -1, caso o ocorra alguma falha no processo de alocação.
     */
    public int algoritmoNFU(Processo p, Escalonador e) {
        if (p.isReferenciado() || p.isModificado()) {
            if (!p.isModificado()) {
                //sobrescreve processo
                int t = p.getTamanho() % tamSeg == 0 ? p.getTamanho() / tamSeg : ((p.getTamanho() + tamSeg) / tamSeg);
                procuraSeguimento(t, p);
            } else {
                if (p.getTamanho() > tamPag) {
                    //Limite de memória atingido
                    return -1;
                } else {
                    int t = p.getTamanho() % tamSeg == 0 ? p.getTamanho() / tamSeg : ((p.getTamanho() + tamSeg) / tamSeg);
                    if (this.procuraSeguimento(t, p) != 0) {
                        do {
                            // Algoritmo/Política
                            //incializar o processo a ser removido.
                            Processo pout = null;
                            //Inicializa iterator
                            Iterator<Map.Entry<Integer, Processo>> it = mapaM.entrySet().iterator();
                            Map.Entry<Integer, Processo> entrada = it.next();
                            // Inicializa contador de vezes que o processo foi referenciado
                            int contador = entrada.getValue().getCount();
                            while (it.hasNext()) {
                                //Verifica se o contador que está no processo é menor do que o contador procurado
                                if (entrada.getValue().getCount() <= contador) {
                                    contador = entrada.getValue().getCount();
                                    //atribui processo a ser removido.
                                    pout = entrada.getValue();
                                }
                            }
                            // Enquanto memória insuficiente 
                            // arranca o processo com menor contador da memória e coloca na swap 
                            removeProcesso(pout);
                            enviaSwap(pout);
                        } while (this.procuraSeguimento(t, p) != 0);
                        return 0;
                    } else {
                        return 0;
                    }
                }
            }
        } else {
            int t = p.getTamanho() % tamSeg == 0 ? p.getTamanho() / tamSeg : ((p.getTamanho() + tamSeg) / tamSeg);
            if (t > tamPag) {
                //Limite memória atingido
                return -1;
            }
            if (this.procuraSeguimento(t, p) != 0) {
                do {
                    // Algoritmo/Política
                    //incializar o processo a ser removido.
                    Processo pout = null;
                    //Inicializa iterator
                    Iterator<Map.Entry<Integer, Processo>> it = mapaM.entrySet().iterator();
                    Map.Entry<Integer, Processo> entrada = it.next();
                    // Inicializa contador de vezes que o processo foi referenciado
                    int contador = entrada.getValue().getCount();
                    while (it.hasNext()) {
                        //Verifica se o contador que está no processo é menor do que o contador procurado
                        if (entrada.getValue().getCount() <= contador) {
                            contador = entrada.getValue().getCount();
                            //atribui processo a ser removido.
                            pout = entrada.getValue();
                        }
                    }
                    // Enquanto memória insuficiente 
                    // arranca o processo com menor contador da memória e coloca na swap 
                    removeProcesso(pout);
                    enviaSwap(pout);
                } while (this.procuraSeguimento(t, p) != 0);
                return 0;
            } else {
                return 0;
            }
        }
        return -1;
    }

    /**
     * Algoritmo Relógio Quando ocorre uma falta de memória o processo apontado
     * pelo ponteiro é removido. Desque que não esteje referenciado.
     *
     * @param p Processo a ser removido
     * @param e Escalonador
     * @return Retorna 0 se obteve sucesso na alocação do processo na memoria e
     * -1, caso o ocorra alguma falha no processo de alocação.
     */
    public int algoritmoRelogio(Processo p, Escalonador e) {
        if (p.isReferenciado() || p.isModificado()) {
            if (!p.isModificado()) {
                //sobrescreve processo
                int t = p.getTamanho() % tamSeg == 0 ? p.getTamanho() / tamSeg : ((p.getTamanho() + tamSeg) / tamSeg);
                procuraSeguimento(t, p);
            } else {
                if (p.getTamanho() > tamPag) {
                    //Limite de memória atingido
                    return -1;
                } else {
                    int t = p.getTamanho() % tamSeg == 0 ? p.getTamanho() / tamSeg : ((p.getTamanho() + tamSeg) / tamSeg);
                    if (this.procuraSeguimento(t, p) != 0) {
                        do {
                            // Algoritmo/Política
                            //Classe relógio
                            Relogio rel = new Relogio();
                            //Processo a ser removido
                            Processo pout = null;
                            Iterator<Map.Entry<Integer, Processo>> it = mapaM.entrySet().iterator();
                            //Preenche relógio para ser feita a politica.
                            while (it.hasNext()) {
                                Map.Entry<Integer, Processo> entrada = it.next();
                                rel.Adiciona(entrada.getValue());
                            }
                            //Verifica processo a ser removido
                            while (pout == null) {
                                if (rel.frente.p.isReferenciado()) {
                                    rel.frente.p.setReferenciado(false);
                                    rel.frente = rel.frente.prox;
                                } else {
                                    pout = rel.Remove();
                                }
                            }
                            // Enquanto memória insuficiente 
                            // arranca pout da memória e coloca na swap 
                            removeProcesso(pout);
                            enviaSwap(pout);
                        } while (this.procuraSeguimento(t, p) != 0);
                        return 0;
                    } else {
                        return 0;
                    }
                }
            }
        } else {
            int t = p.getTamanho() % tamSeg == 0 ? p.getTamanho() / tamSeg : ((p.getTamanho() + tamSeg) / tamSeg);
            if (t > tamPag) {
                //Limite de memória atingido
                return -1;
            }
            if (this.procuraSeguimento(t, p) != 0) {
                do {
                    // Algoritmo/Política
                    //Classe relógio
                    Relogio rel = new Relogio();
                    //Processo a ser removido
                    Processo pout = null;
                    Iterator<Map.Entry<Integer, Processo>> it = mapaM.entrySet().iterator();
                    //Preenche relógio para ser feita a politica.
                    while (it.hasNext()) {
                        Map.Entry<Integer, Processo> entrada = it.next();
                        rel.Adiciona(entrada.getValue());
                    }
                    //Verifica processo a ser removido
                    while (pout == null) {
                        if (rel.frente.p.isReferenciado()) {
                            rel.frente.p.setReferenciado(false);
                            rel.frente = rel.frente.prox;
                        } else {
                            pout = rel.Remove();
                        }
                    }
                    // Enquanto memória insuficiente 
                    // arranca pout da memória e coloca na swap 
                    removeProcesso(pout);
                    enviaSwap(pout);
                } while (this.procuraSeguimento(t, p) != 0);
                return 0;
            } else {
                return 0;
            }
        }
        return -1;
    }

    /**
     * Algoritmo Envelhecimento mantém um vetor de oito posição de forma que
     * quando o processo é referenciado ou desreferenciado é inserido na cabeça
     * desse vetor o processo a ser retirado é sempre o que contiver menos bit 1
     *
     * @param p Processo a ser retirado
     * @param e Escalonador
     * @return Retorna 0 se obteve sucesso na alocação do processo na memoria e
     * -1, caso o ocorra alguma falha no processo de alocação.
     */
    public int algoritmoEnvelhecimento(Processo p, Escalonador e) {
        if (p.isReferenciado() || p.isModificado()) {
            if (!p.isModificado()) {
                //sobrescreve processo
                int t = p.getTamanho() % tamSeg == 0 ? p.getTamanho() / tamSeg : ((p.getTamanho() + tamSeg) / tamSeg);
                procuraSeguimento(t, p);
            } else {
                if (p.getTamanho() > tamPag) {
                    //Limite de memória atingido
                    return -1;
                } else {
                    int t = p.getTamanho() % tamSeg == 0 ? p.getTamanho() / tamSeg : ((p.getTamanho() + tamSeg) / tamSeg);
                    if (this.procuraSeguimento(t, p) != 0) {
                        do {
                            // Algoritmo/Política
                            Processo pout = new Processo();//processo que será retornado
                            pout.setCount(0);//seta o contador em zero para fins de comparação
                            //inicializa interator
                            Iterator<Map.Entry<Integer, Processo>> it = mapaM.entrySet().iterator();
                            while (it.hasNext()) {
                                Map.Entry<Integer, Processo> entrada = it.next();
                                for (int i = 0; i < 8; i++) {
                                    //se a posição do vetor for true foi referenciado
                                    if (entrada.getValue().getAging()[i]) {
                                        //incrementa o contatador em quantas vezes o mesmo foi referenciado
                                        entrada.getValue().setCount(entrada.getValue().getCount() + 1);
                                    }
                                }
                            }
                            while (it.hasNext()) {
                                Map.Entry<Integer, Processo> entrada = it.next();
                                //procura pelo processo que foi referenciado menos vezes
                                if (entrada.getValue().getCount() < pout.getCount()) {
                                    //O processo que foi referenciado menos vezes será retirado
                                    pout = entrada.getValue();
                                    /*
                                     * Caso um processo tenha sido referenciado um minimo de vezes iguais
                                     * o processo que sera retirado será o que tem um maior número 
                                     * de zeros a direita
                                     */
                                } else if (entrada.getValue().getCount() == pout.getCount()) {
                                    int countEntrada = 0;
                                    int countPout = 0;
                                    for (int i = 0; i < 8; i++) {
                                        //conta quantos zeros tem a direita do processo que é uma entrada na hash
                                        if (!entrada.getValue().getAging()[i]) {
                                            countEntrada++;
                                        } else {
                                            break;
                                        }
                                        //Conta quantos zeros tem a direita de pout que já é o retorno
                                        if (!pout.getAging()[i]) {
                                            countPout++;
                                        } else {
                                            break;
                                        }
                                    }
                                    //caso o número de zeros a direita da entrada na hash for maior ele será retirado
                                    if (countEntrada > countPout) {
                                        pout = entrada.getValue();
                                    }
                                    //caso contrario o processo a ser retirado permanece sendo pout
                                    removeProcesso(pout);
                                    enviaSwap(pout);
                                }
                            }
                            // Enquanto memória insuficiente 
                            // arranca pout da memória e coloca na swap 
                        } while (this.procuraSeguimento(t, p) != 0);
                        return 0;
                    } else {
                        return 0;
                    }
                }
            }
        } else {
            int t = p.getTamanho() % tamSeg == 0 ? p.getTamanho() / tamSeg : ((p.getTamanho() + tamSeg) / tamSeg);
            if (t > tamPag) {
                //Limite de memória antingido
                return -1;
            }
            if (this.procuraSeguimento(t, p) != 0) {
                do {
                    // Algoritmo/Política
                    Processo pout = new Processo();//processo que será retornado
                    pout.setCount(0);//seta o contador em zero para fins de comparação
                    //inicializa interator
                    Iterator<Map.Entry<Integer, Processo>> it = mapaM.entrySet().iterator();
                    while (it.hasNext()) {
                        Map.Entry<Integer, Processo> entrada = it.next();
                        for (int i = 0; i < 8; i++) {
                            //se a posição do vetor for true foi referenciado
                            if (entrada.getValue().getAging()[i]) {
                                //incrementa o contatador em quantas vezes o mesmo foi referenciado
                                entrada.getValue().setCount(entrada.getValue().getCount() + 1);
                            }
                        }
                    }
                    while (it.hasNext()) {
                        Map.Entry<Integer, Processo> entrada = it.next();
                        //procura pelo processo que foi referenciado menos vezes
                        if (entrada.getValue().getCount() < pout.getCount()) {
                            //O processo que foi referenciado menos vezes será retirado
                            pout = entrada.getValue();
                            /*
                             * Caso um processo tenha sido referenciado um minimo de vezes iguais
                             * o processo que sera retirado será o que tem um maior número 
                             * de zeros a direita
                             */
                        } else if (entrada.getValue().getCount() == pout.getCount()) {
                            int countEntrada = 0;
                            int countPout = 0;
                            for (int i = 0; i < 8; i++) {
                                //conta quantos zeros tem a direita do processo que é uma entrada na hash
                                if (!entrada.getValue().getAging()[i]) {
                                    countEntrada++;
                                } else {
                                    break;
                                }
                                //Conta quantos zeros tem a direita de pout que já é o retorno
                                if (!pout.getAging()[i]) {
                                    countPout++;
                                } else {
                                    break;
                                }
                            }
                            //caso o número de zeros a direita da entrada na hash for maior ele será retirado
                            if (countEntrada > countPout) {
                                pout = entrada.getValue();
                            }
                            //caso contrario o processo a ser retirado permanece sendo pout
                            removeProcesso(pout);
                            enviaSwap(pout);
                        }
                    }
                    // Enquanto memória insuficiente 
                    // arranca pout da memória e coloca na swap
                } while (this.procuraSeguimento(t, p) != 0);
                return 0;
            } else {
                return 0;
            }
        }
        return -1;
    }
}
